/*
 * Copyright (c) 2009 Robert Esser
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.e2ser.petri;

import java.lang.Math;

/**
 *
 * <p>Title: Petri Net Editor/Simulator</p>
 * <p>Description: </p>
 * <p>Copyright: Copyright (c) 2009</p>
 * <p>Company: </p>
 * @author Rob Esser
 * @version 1.0
 */
public class RobPoint {

  /** when close enough is good enough */
  static final double error = 0.0001;

  public double x = 0.0;
  public double y = 0.0;

  public RobPoint(int x, int y) {
    // create a point
    this.x = (double) x;
    this.y = (double) y;
  }

  public RobPoint(double x, double y) {
    // create a point
    this.x = x;
    this.y = y;
  }

  public RobPoint sub(RobPoint a, RobPoint b) {
    // return the difference between the two points
    return new RobPoint(a.x - b.x, a.y - b.y);
  }

  public RobPoint sub(RobPoint b) {
    // return the difference between the two points
    return sub(this, b);
  }

  public RobPoint add(RobPoint a, RobPoint b) {
    // return the sum between the two points
    return new RobPoint(a.x + b.x, a.y + b.y);
  }

  public RobPoint add(RobPoint b) {
    // return the sum between the two points
    return add(this, b);
  }

  public RobPoint mult(RobPoint a, RobPoint b) {
    // return the product between the two points
    return new RobPoint(a.x * b.x, a.y * b.y);
  }

  public RobPoint mult(RobPoint b) {
    // return the product between the two points
    return mult(this, b);
  }

  public RobPoint mult(double d) {
    // mult x and y by d
    return new RobPoint(this.x * d, this.y * d);
  }

  public RobPoint div(double d) {
    // divide x and y by d
    return new RobPoint(this.x / d, this.y / d);
  }

  public double dotProduct(RobPoint a) {
    // return the dot product of two points
    return (this.x * a.x) + (this.y * a.y);
  }

  public double radius() {
    // return the radius in polar coordinates
    return sqrt(this.dotProduct(this));
  }

  public double theta() {
    // return the angle between the points and the origin
    //Note arctan works 0..1.0 need to mod arctan to do the quadrant identification
    //return arctan(y, x);
    return 0.0;
  }

  public RobPoint unitVector() {
    // return the point a unit vector
    return this.div(this.radius());
  }

  public RobPoint normal() {
    // return the normal vector
    return (new RobPoint(0.0 - this.y, this.x)).unitVector();
  }

//  public static double arctan(double x, double y) {
//    return arctan(x/y, error);
//  }

  public static double sqrt(double w) {
    if (w <= error) {
      return 0.0;
    } else {
      return findRoot(w, w / 2);
    }
  }

  private static double findRoot(double w, double g) {
    double newGuess = g - ((g * g) - w) / (2 * g);
    if (Math.abs(newGuess - g) < Math.abs(g * error)) {
      return newGuess;
    } else {
      return findRoot(w, newGuess);
    }
  }

  /**
   * Works for 0 <= x <= 1.0
   */
//  private static double arctan(double x, double tolerance) {
//    double x2 = x * x;
//    double arctan = 0;
//    double power = x;
//    double denominator = 1;
//    double sign = 1;
//    while (power / denominator >= tolerance) {
//      arctan += sign * power / denominator;
//      power *= x2;
//      denominator += 2;
//      sign *= -1;
//    }
//    return arctan;
//  }

}
